using System;
using System.Collections.Generic;
using Subsync.Core.Sync;

namespace Subsync.GUI
{
	/// <summary>
	/// Author: Steven Goh Jian Wen
	/// </summary>
	public enum LocalAdd
    {
		Media,
		Sync,
	}
	
	public class AddLocalFolderManager
	{
        //Class Variables
		private string path_to_folder;
		private string new_sync_name;
		private string description;
		private string icon;
		private bool automatic_conflict_management;
		private string repo_url;
		private LocalAdd method;
		private string sync_name;
		private string media_path;

		private bool has_conflicts = false;
		private bool has_errors = false;
	 	private string error_description = "";

        //Class Properties
        public bool HasConflicts
        {
            get { return has_conflicts; }
        }

        public bool HasErrors
        {
            get { return has_errors; }
        }

        public string ErrorMsg
        {
            get { return error_description; }
        }

		/// <summary>
		/// Get path of folder to be synced.
		/// </summary>
		public SyncAddError Step1 (string path_to_folder)
		{
            if (!Subsync.GUI.Tools.FolderExists(path_to_folder))
            {
                return SyncAddError.FolderDoesNotExist;
            }
			if (Subsync.GUI.Tools.IsVersioned (path_to_folder))
            {
				return SyncAddError.WorkingCopyPathError;
			}
            if (Subsync.GUI.Tools.IsInsideAnotherWorkingCopy(path_to_folder))
            {
                return SyncAddError.WorkingCopyPathError;
            }
			this.path_to_folder = path_to_folder;
			return SyncAddError.Ok;
		}
		
		/// <summary>
		/// Method of local sync
		/// </summary>
		/// <param name="method">
		/// A <see cref="LocalAdd"/>
		/// </param>
		/// <param name="sync_name">
		/// A <see cref="System.String"/>
		/// </param>
		/// <param name="media_path">
		/// A <see cref="System.String"/>
		/// </param>
		public SyncAddError Step2 (LocalAdd method, string sync_name, string media_path)
		{
			if (method == LocalAdd.Media) {
				//check that it is a repo
				if (!Subsync.GUI.Tools.IsRepo (media_path))
					return SyncAddError.NotRepo;
				this.media_path = media_path;
				this.repo_url = "file://" + this.media_path.Replace (System.IO.Path.DirectorySeparatorChar, '/');
			}
			else if (method == LocalAdd.Sync) {
				//check that sync_name exists
				if (!Subsync.GUI.Tools.SyncExists (sync_name))
					return SyncAddError.SyncDoesNotExist;
				this.sync_name = sync_name;
			}
			this.method = method;
			return SyncAddError.Ok;
		}
		
		/// <summary>
		/// Get new sync name
		/// </summary>
		/// <param name="new_sync_name">
		/// A <see cref="System.String"/>
		/// </param>
		public SyncAddError Step3 (string new_sync_name)
		{
			if (Subsync.GUI.Tools.SyncExists (new_sync_name))
				return SyncAddError.SyncNameExists;
			if (new_sync_name.Trim () == "")
				return SyncAddError.EmptyString;
			this.new_sync_name = new_sync_name;
			return SyncAddError.Ok;
		}
		
		/// <summary>
		/// Sync description
		/// </summary>
		/// <param name="desc">
		/// A <see cref="System.String"/>
		/// </param>
		public SyncAddError Step4 (string desc)
		{
			this.description = desc;
			return SyncAddError.Ok;
		}
		
		/// <summary>
		/// Get conflict management option
		/// </summary>
		/// <param name="cm">
		/// A <see cref="System.Boolean"/>
		/// </param>
		public SyncAddError Step5(bool conflict_m) {
			this.automatic_conflict_management = conflict_m;
			return SyncAddError.Ok;
		}
		
		/// <summary>
		/// Get Icon Path
		/// </summary>
		/// <param name="icon_path">
		/// A <see cref="System.String"/>
		/// </param>
		public SyncAddError Step6 (string icon_path)
		{
			if (System.IO.File.Exists (icon_path))
				this.icon = icon_path;
			return SyncAddError.Ok;
		}
		
		public void Execute ()
		{
			Sync sync = new Sync ();
			
			sync.GuiConflict += HandleSGuiConflict;
			sync.gui = true;
			sync.icon = this.icon;
			sync.description = this.description;
			try {
				if (method == LocalAdd.Sync)
					sync.AddSync (SyncType.Local, this.sync_name, this.new_sync_name, this.path_to_folder, "", this.automatic_conflict_management);
				else
					sync.AddSync (SyncType.Network, "", this.new_sync_name, this.path_to_folder, this.repo_url, this.automatic_conflict_management);
			}
			catch (SyncNotFound) {
				this.has_errors = true;
				this.error_description = "Sync not found.";
			}
			catch (FolderDoesNotExist) {
				this.has_errors = true;
				this.error_description = "Folder does not exist.";
			}
			catch (RepositoryNotFound) {
				this.has_errors = true;
				this.error_description = "Repository cannot be found.";
			}
			catch (SyncNameConflict) {
				this.has_errors = true;
				this.error_description = "Sync name conflicts.";
			}
			catch (PathAlreadyAWorkingCopy) {
				this.has_errors = true;
				this.error_description = "Directory is a SVN working copy, cannot proceed.";
			} catch (DiskSpaceException) {
				this.has_errors = true;
				this.error_description = "Disk is full, please clear some space and try again.";
			}
			catch (Exception) {
				this.has_errors = true;
				this.error_description = "An unknown error has occurred.";
			}
		}

		void HandleSGuiConflict (object source, Sync s)
		{
			this.has_conflicts = true;
			Gtk.Application.Invoke (delegate {
				ConflictDialog c = new ConflictDialog (s,false);
				c.Show ();
			});
		}
	}
}
